package provisioning.ranjan;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.model.PutMetricAlarmRequest;
import commons.client.Scheduler;
import commons.monitor.CloudWatchReceiver;

public class RanjanDataCalculator {
	
	private Scheduler scheduler;
	private AmazonCloudWatch monitor;
	private RanjanCollector collector;
	private double targetUtilization;
	private Date startInterval;
	private Date endInterval;
	
	public RanjanDataCalculator(RanjanCollector collector) {
		monitor = CloudWatchReceiver.getMonitor();
		this.collector = collector;
		this.targetUtilization = RanjanCollector.TARGET_UTILIZATION;
		//TODO How to figure out this
		this.startInterval = new Date();
		this.endInterval = new Date();
		
		this.scheduler =Scheduler.getScheduler();
	}
	
	private double getAverageCPUUtilization() {
		double average = 0;
		List<Double> averageCollection = collector.averageCPUUtilizationForAGroup(startInterval, endInterval, "");
		
		for(double a : averageCollection) {
			average += a; 
		} average = average/averageCollection.size();
		
		return average;
	}
	
	private double calculateD() {
		double complete = collector.numberOfCompleteRequests();
		
		double d = getAverageCPUUtilization()/complete;
		return d;
	}
	
	private double calculateU() {
		double arrivals = collector.numberOfArrivals(startInterval, endInterval, "");
		double complete = collector.numberOfCompleteRequests();
		
		double uLign = Math.max(arrivals, complete) * calculateD();
		return uLign;
	}
	
	public int evaluateNumberOfServersForNextInterval() {
		int activeServers = collector.numberOfCurrentServers();
		
		int newNumberOfServers = (int) Math.ceil(calculateU() * activeServers/targetUtilization);
		return Math.max(1, newNumberOfServers) - collector.numberOfCurrentServers();
	}
	
	public void putAlarmMetric() {
		PutMetricAlarmRequest alarm = new PutMetricAlarmRequest();
		
		List<String> alarmActions = new ArrayList<String>();
		alarmActions.add(scheduler.ranjanScaling());
		
		monitor.putMetricAlarm(alarm);

		if(evaluateNumberOfServersForNextInterval() != 0) {
			alarm.setAlarmActions(alarmActions);
			alarm.setActionsEnabled(true);
		} else {
			alarm.setActionsEnabled(false);
		}
	}
}
